package com.shulidata.mock.utils.sec;

import javax.crypto.Cipher;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 数据加解密
 */
public class RSACoderUtil extends BaseCoderUtil {

    /**
     * 数据验证
     *
     * @param charset 编码格式
     * @param ciphertext 验证数据
     * @return
     */
    public static String encryptWithSHA(String ciphertext, String charset) throws Exception {
        byte[] data = encryptSHA(ciphertext.getBytes(charset));
        String shadata = BaseCoderUtil.bcd2Str(data);
        return shadata;
    }

    /**
     * 私钥加密
     *
     * @param plaintext 明文
     * @param key 加签密钥
     * @param algorithm 加签算法
     * @return
     */
    public static String encryptByPrivateKey(String plaintext, String key, String algorithm, int encryptSize)
                                                                                           throws Exception {
        //对私钥解密
        byte[] keyBytes = decryptBASE64(key);

        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PrivateKey privateKey1 = keyFactory.generatePrivate(pkcs8KeySpec);

        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey1);

        // 加密时超过245字节就报错。为此采用分段加密的办法来加密
        String[] datas = BaseCoderUtil.splitString(plaintext, encryptSize);
        String ensignData = "";
        for (String s : datas) {
            ensignData += BaseCoderUtil.bcd2Str(cipher.doFinal(s.getBytes()));
        }

        return ensignData;
    }

    /**
     * 公钥加密
     *
     * @param plaintext 明文
     * @param key 加密密钥
     * @param algorithm 加密算法
     * @return
     */
    public static String encryptByPublicKey(String plaintext, String key, String algorithm, int encryptSize)
                                                                                           throws Exception {
        //对公钥解密
        byte[] keyBytes = decryptBASE64(key);

        //取公钥
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        Key publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);

        //对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey2);

        // 加密时超过245字节就报错。为此采用分段加密的办法来加密
        String[] datas = BaseCoderUtil.splitString(plaintext, encryptSize);
        String encryptData = "";
        for (String s : datas) {
            encryptData += BaseCoderUtil.bcd2Str(cipher.doFinal(s.getBytes()));
        }

        return encryptData;
    }

    /**
     * 私钥解密
     *
     * @param ciphertext 密文
     * @param key 解密密钥
     * @param algorithm 解密算法
     * @return
     */
    public static String decryptByPrivateKey(String ciphertext, String key, String algorithm, int decryptSize)
                                                                                             throws Exception {
        //对私钥解密
        byte[] keyBytes = decryptBASE64(key);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8KeySpec);

        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey2);

        //数据格式转换
        byte[] bytes = ciphertext.getBytes();
        byte[] bcd = BaseCoderUtil.ASCII_To_BCD(bytes, bytes.length);

        // 解密时超过256字节就报错。为此采用分段解密的办法来解密
        String designData = "";
        byte[][] arrays = BaseCoderUtil.splitArray(bcd, decryptSize);
        for (byte[] arr : arrays) {
            designData += new String(cipher.doFinal(arr));
        }

        return designData;
    }

    /**
     * 公钥解密
     * @param ciphertext 密文
     * @param key 密钥
     * @param algorithm 解密算法
     * @return String data 解密数据
     */
    public static String decryptByPublicKey(String ciphertext, String key, String algorithm, int decryptSize)
                                                                                                throws Exception {
        //对公钥解密
        byte[] keyBytes = decryptBASE64(key);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        PublicKey publicKey1 = keyFactory.generatePublic(x509KeySpec);

        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey1);

        //数据格式转换
        byte[] bytes = ciphertext.getBytes();
        byte[] bcd = BaseCoderUtil.ASCII_To_BCD(bytes, bytes.length);

        //解密时超过256字节就报错。为此采用分段解密的办法来解密
        String decryptData = "";
        byte[][] arrays = BaseCoderUtil.splitArray(bcd, decryptSize);
        for (byte[] arr : arrays) {
            decryptData += new String(cipher.doFinal(arr));
        }

        return decryptData;
    }

}